<?php

declare(strict_types=1);

namespace RX\Event;

use EasySwoole\Component\Di;
use EasySwoole\EasySwoole\Config;
use EasySwoole\Http\Request;
use EasySwoole\Http\Response;
use EasySwoole\ORM\Db\Config as DbConfig;
use EasySwoole\ORM\Db\Connection;
use EasySwoole\ORM\DbManager;
use EasySwoole\Pool\Exception\Exception;
use EasySwoole\Redis\Config\RedisConfig;
use EasySwoole\RedisPool\RedisPool;
use EasySwoole\RedisPool\RedisPoolException;
use EasySwoole\Utility\File;
use RX\Helpers\StringHelper;
use EasySwoole\EasySwoole\Crontab\Crontab;
use EasySwoole\Component\Process\Manager as ProcessManager;
use EasySwoole\Component\Process\Config as ProcessConfig;
use Swoole\Http\Status;

class GlobalEvent
{
    public static function cors(Request $request, Response $response, ?callable $call = null): bool
    {
        $allowHeaders = 'Content-Type,Authorization, X-Requested-With, responseType';
        $response->withHeader('Access-Control-Allow-Origin', '*');
        $response->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
        $response->withHeader('Access-Control-Allow-Credentials', 'true');
        $response->withHeader('Access-Control-Allow-Headers', $allowHeaders);
        if ($request->getMethod() === 'OPTIONS') {
            $response->withStatus(Status::OK);
            return false;
        }
        if (StringHelper::matchWildcard("*favicon*", $request->getUri()->getPath())) {
            $response->withStatus(Status::OK);
            return false;
        }
        if (!is_null($call)) {
            return call_user_func($call, $request, $response);
        }
        return true;
    }

    /**
     * @param string|null $path
     */
    public static function config(?string $path = null): void
    {
        $path = $path ?? EASYSWOOLE_ROOT . '/App/Configs';
        $data = [];
        $scan = File::scanDirectory($path);
        if (!$scan) {
            return;
        }
        $files = $scan['files'];
        if (StringHelper::isEmpty($files)) {
            return;
        }
        foreach ($files as $file) {
            $name        = StringHelper::basename($file, '.php');
            $data[$name] = require_once($file);
        }
        Config::getInstance()->merge($data);
    }

    /**
     * 服务
     *
     * @param string|null $path
     * @param string|null $namespace
     */
    public static function serviceDi(?string $path = null, string $namespace = 'App\\Service'): void
    {
        $path = $path ?? EASYSWOOLE_ROOT . '/App/Service';

        $scan = File::scanDirectory($path);
        if (!$scan) {
            return;
        }
        $files = $scan['files'];
        if (StringHelper::isEmpty($files)) {
            return;
        }
        foreach ($files as $file) {
            $name  = StringHelper::basename($file, '.php');
            $file  = substr($file, 0, -4);
            $class = $namespace . implode('\\', array_map(function ($str) {
                    return StringHelper::ucfirst($str);
            }, StringHelper::explode(str_replace($path, '', $file), '/')));
            Di::getInstance()->alias($name, $class)->set($class, $class);
        }
    }


    /**
     * redis
     *
     * @param string $config
     *
     * @throws Exception
     * @throws \EasySwoole\RedisPool\Exception\Exception
     * @throws RedisPoolException
     */
    public static function redis(string $config = 'REDIS')
    {
        $redisConfig = StringHelper::config($config);
        foreach ($redisConfig as $key => $value) {
            $configPool = RedisPool::getInstance()->register(new RedisConfig($value), $key);
            $configPool->setGetObjectTimeout($value['getObjectTimeout']);
            $configPool->setIntervalCheckTime($value['intervalCheckTime']);
            $configPool->setMaxIdleTime($value['maxIdleTime']);
            $configPool->setMinObjectNum($value['minObjectNum']);
            $configPool->setMaxObjectNum($value['maxObjectNum']);
        }
    }


    /**
     * mysql
     *
     */
    public static function mysql()
    {
        $dbConfig = Config::getInstance()->getConf('DATABASE');
        foreach ($dbConfig as $key => $val) {
            $config = new DbConfig($val);
            DbManager::getInstance()->addConnection(new Connection($config), $key);
        }
    }


    /**
     * 进程
     *
     * @param array $classes
     * @param bool $isOpen
     */
    public static function process(array $classes, bool $isOpen = true)
    {
        if (!$isOpen) {
            return;
        }
        foreach ($classes as $class) {
            $processConfig = new ProcessConfig();
            $processConfig->setProcessName($class);
            $processConfig->setProcessGroup($class);
            $processConfig->setRedirectStdinStdout(false);
            $processConfig->setPipeType($processConfig::PIPE_TYPE_SOCK_DGRAM);
            $processConfig->setEnableCoroutine(true);
            $processConfig->setMaxExitWaitTime(3);
            ProcessManager::getInstance()->addProcess(new $class($processConfig));
        }
    }

    /**
     * task
     * @param array $classes
     * @param bool $isOpen
     */
    public static function task(array $classes, bool $isOpen = true)
    {
        if (!$isOpen) {
            return;
        }
        foreach ($classes as $class) {
            Crontab::getInstance()->addTask($class);
        }
    }
}
